package com.secsbrain.engine.web.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.secsbrain.engine.biz.constant.EnumDefinition;
import com.secsbrain.engine.biz.constant.ProcessParamConstant;
import com.secsbrain.engine.biz.utils.ParseDtoUtil;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.secsbrain.common.ErrorCodeEnum;
import com.secsbrain.common.ResponseVo;
import com.secsbrain.engine.client.constant.ProcessKeyConstant;
import com.secsbrain.engine.client.constant.TaskDefineKeyConstant;
import com.secsbrain.engine.client.iface.WorkSheetFlowService;
import com.secsbrain.engine.client.model.ProcessDeal;
import com.secsbrain.engine.client.model.ProcessDto;
import com.secsbrain.engine.client.model.StartProcessParam;
import com.secsbrain.engine.client.model.TaskDto;

/**
 * 工单流程相关控制层
 *
 * @author zhaoyi
 */
@RestController
@EnableEurekaClient
public class WorkSheetFlowController implements WorkSheetFlowService{

	private static final Logger logger = LoggerFactory.getLogger(WorkSheetFlowController.class);

	@Autowired
	private RepositoryService repositoryService;

	@Autowired
	private TaskService taskService;

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private HistoryService historyService;

	/**
	 * 功能描述: <br>
	 * 创建工单
	 *
	 */
	@SuppressWarnings("unchecked")
	public ResponseVo<ProcessDto> create(@RequestBody StartProcessParam startProcessParam) {
		startProcessParam.setProcessDefinitionKey(ProcessKeyConstant.WORK_SHEET_KEY);
		Assert.hasText(startProcessParam.getStartUserId(), "启动用户不能为空");

		logger.debug("工单创建流程开始...{}", JSON.toJSONString(startProcessParam));

		List<ProcessDefinition> processDefinition = repositoryService.createProcessDefinitionQuery()
				.processDefinitionKey(startProcessParam.getProcessDefinitionKey()).list();
		if (processDefinition == null) {
			return ErrorCodeEnum.ERROR_COMMON_CHECK.getResponseVo("流程定义key不存在");
		}

		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
		// 设置启动用户
		processEngine.getIdentityService().setAuthenticatedUserId(startProcessParam.getStartUserId());

		// 启动流程
		ProcessInstance processInstance = runtimeService
				.startProcessInstanceByKey(startProcessParam.getProcessDefinitionKey());

		// 设置任务owner
		Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
		taskService.setOwner(task.getId(), startProcessParam.getStartUserId());

		ProcessDto processDto = new ProcessDto();
		processDto.setProcessInstanceId(processInstance.getId());
		processDto.setStartUserId(processInstance.getStartUserId());
		processDto.setProcessDefinitionKey(processInstance.getProcessDefinitionKey());

		logger.debug("工单创建流程成功！返回：{}", JSON.toJSONString(processDto));
		return ResponseVo.getSuccessResponse(processDto);
	}

	/**
	 * 功能描述: <br>
	 * 认领工单流程
	 *
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public ResponseVo<String> claim(@RequestBody ProcessDeal processDeal) {
		Assert.hasText(processDeal.getProcessInstanceId(), "流程实例ID不能为空");
		Assert.hasText(processDeal.getUserId(), "用户ID不能为空");

		Task task = taskService.createTaskQuery().processInstanceId(processDeal.getProcessInstanceId())
				.taskDefinitionKey(TaskDefineKeyConstant.CREATE_KEY).singleResult();
		if (task == null) {
			return ErrorCodeEnum.ERROR_COMMON_CHECK.getResponseVo("当前流程不正确");
		}

		Map<String, Object> vars = new HashMap<String, Object>();
		vars.put(ProcessParamConstant.ASSIGNEE, processDeal.getUserId());
    	vars.put("agree", EnumDefinition.ApprovalStatus.AGREE.getCode());
		taskService.complete(task.getId(), vars);
		
		Task newTask = taskService.createTaskQuery().processInstanceId(processDeal.getProcessInstanceId()).singleResult();
		taskService.setOwner(newTask.getId(), task.getOwner());

		logger.debug("认领工单流程成功！");
		return ResponseVo.getSuccessResponse(processDeal.getProcessInstanceId());
	}

	/**
	 * 功能描述: <br>
	 * 结束工单流程
	 *
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public ResponseVo<String> finish(@RequestBody ProcessDeal processDeal) {
		Assert.hasText(processDeal.getProcessInstanceId(), "流程实例ID不能为空");
		Assert.hasText(processDeal.getUserId(), "用户ID不能为空");

		Task task = taskService.createTaskQuery().processInstanceId(processDeal.getProcessInstanceId())
				.taskDefinitionKey(TaskDefineKeyConstant.DEAL_KEY).singleResult();
		if (task == null) {
			return ErrorCodeEnum.ERROR_COMMON_CHECK.getResponseVo("当前流程不正确");
		}
		if(!task.getAssignee().equals(processDeal.getUserId())){
			return ErrorCodeEnum.ERROR_COMMON_CHECK.getResponseVo("工单处理人与当前用户不匹配");
		}
		Map<String, Object> vars = new HashMap<String, Object>();
		vars.put(ProcessParamConstant.ASSIGNEE, processDeal.getUserId());
		taskService.complete(task.getId(), vars);
		
		Task newTask = taskService.createTaskQuery().processInstanceId(processDeal.getProcessInstanceId()).singleResult();
		taskService.setOwner(newTask.getId(), task.getOwner());

		logger.debug("结束工单流程成功！");
		return ResponseVo.getSuccessResponse(processDeal.getProcessInstanceId());
	}
	
	/**
	 * 功能描述: <br>
	 * 确认工单流程
	 *
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public ResponseVo<String> confirm(@RequestBody ProcessDeal processDeal) {
		Assert.hasText(processDeal.getProcessInstanceId(), "流程实例ID不能为空");
		Assert.hasText(processDeal.getUserId(), "用户ID不能为空");

		Task task = taskService.createTaskQuery().processInstanceId(processDeal.getProcessInstanceId())
				.taskDefinitionKey(TaskDefineKeyConstant.FINISH_KEY).singleResult();
		if (task == null) {
			task = taskService.createTaskQuery().processInstanceId(processDeal.getProcessInstanceId())
					.taskDefinitionKey(TaskDefineKeyConstant.CREATE_KEY).singleResult();
		}
		
		if (task == null) {
			return ErrorCodeEnum.ERROR_COMMON_CHECK.getResponseVo("当前流程不正确");
		}
		if(!task.getOwner().equals(processDeal.getUserId())){
			return ErrorCodeEnum.ERROR_COMMON_CHECK.getResponseVo("工单与当前用户不匹配");
		}

		Map<String, Object> vars = new HashMap<String, Object>();
    	vars.put("agree", EnumDefinition.ApprovalStatus.REFUSE.getCode());
		taskService.complete(task.getId(), vars);

		logger.debug("确认工单流程成功！");
		return ResponseVo.getSuccessResponse(processDeal.getProcessInstanceId());
	}

	/* (non-Javadoc)
	 * @see WorkSheetFlowService#transfer(ProcessDeal)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public ResponseVo<String> transfer(@RequestBody ProcessDeal processDeal) {
		Assert.hasText(processDeal.getProcessInstanceId(), "流程实例ID不能为空");
		Assert.hasText(processDeal.getUserId(), "当前用户ID不能为空");
		Assert.hasText(processDeal.getRoleCode(), "转移的用户ID不能为空");
		
		Task task = taskService.createTaskQuery().processInstanceId(processDeal.getProcessInstanceId())
				.taskDefinitionKey(TaskDefineKeyConstant.DEAL_KEY).singleResult();
		if (task == null) {
			return ErrorCodeEnum.ERROR_COMMON_CHECK.getResponseVo("当前流程不正确");
		}
		if(!task.getAssignee().equals(processDeal.getUserId())){
			return ErrorCodeEnum.ERROR_COMMON_CHECK.getResponseVo("工单处理人与当前用户不匹配");
		}
		
		taskService.setAssignee(task.getId(), processDeal.getRoleCode());
		
		logger.debug("转移工单流程成功！");
		return ResponseVo.getSuccessResponse(processDeal.getProcessInstanceId());
	}
	
	/**
	 * 功能描述: <br>
	 * 查询运维工单任务列表
	 *
	 * @param assignUser
	 *            用户
	 * @param roleCode
	 *            角色编号
	 * @param taskDefineKey
	 *            任务key
	 * @return
	 */
	@RequestMapping(value = "/workSheetFlow/opsTasklist", method = RequestMethod.GET)
	public ResponseVo<List<TaskDto>> opsTasklist(String assignUser, String roleCode, String taskDefineKey) {
		Assert.hasText(assignUser, "用户不能为空");
		Assert.hasText(roleCode, "角色编号不能为空");

		logger.debug("查询运维工单任务列表。。。assignUser:{}", assignUser);

		TaskQuery taskQuery = taskService.createTaskQuery().processDefinitionKey(ProcessKeyConstant.WORK_SHEET_KEY);
		if (TaskDefineKeyConstant.CREATE_KEY.equals(taskDefineKey)) {
			taskQuery.taskAssignee(roleCode);
		} else {
			taskQuery.taskAssignee(assignUser);
		}
		if (StringUtils.isNotEmpty(taskDefineKey)) {
			taskQuery.taskDefinitionKey(taskDefineKey);
		}

		List<TaskDto> list = ParseDtoUtil.parseTaskList(taskQuery.list());
		return ResponseVo.getSuccessResponse(list.size(), list);
	}

	/**
	 * 功能描述: <br>
	 * 查询所有工单任务列表
	 *
	 * @param taskDefineKey
	 *            任务key
	 * @return
	 */
	@RequestMapping(value = "/workSheetFlow/allTasklist", method = RequestMethod.GET)
	public ResponseVo<List<TaskDto>> allTasklist(String taskDefineKey) {
		logger.debug("查询所有工单任务列表。。。");

		TaskQuery taskQuery = taskService.createTaskQuery().processDefinitionKey(ProcessKeyConstant.WORK_SHEET_KEY);
		if (StringUtils.isNotEmpty(taskDefineKey)) {
			taskQuery.taskDefinitionKey(taskDefineKey);
		}

		List<TaskDto> list = ParseDtoUtil.parseTaskList(taskQuery.list());
		return ResponseVo.getSuccessResponse(list.size(), list);
	}
	
	/**
	 * 功能描述: <br>
	 * 查询需求方工单任务列表
	 *
	 * @param ownerUser
	 *            用户
	 * @param taskDefineKey
	 *            任务key
	 * @return
	 */
	@RequestMapping(value = "/workSheetFlow/demanderTasklist", method = RequestMethod.GET)
	public ResponseVo<List<TaskDto>> demanderTasklist(String ownerUser, String taskDefineKey) {
		Assert.hasText(ownerUser, "用户不能为空");

		logger.debug("查询需求方工单任务列表。。。ownerUser:{}", ownerUser);

		TaskQuery taskQuery = taskService.createTaskQuery().processDefinitionKey(ProcessKeyConstant.WORK_SHEET_KEY);
		taskQuery.taskOwner(ownerUser);
		if (StringUtils.isNotEmpty(taskDefineKey)) {
			taskQuery.taskDefinitionKey(taskDefineKey);
		}
		
		historyService.createHistoricProcessInstanceQuery()
			.processDefinitionKey(ProcessKeyConstant.WORK_SHEET_KEY).startedBy(ownerUser);

		List<TaskDto> list = ParseDtoUtil.parseTaskList(taskQuery.list());
		return ResponseVo.getSuccessResponse(list.size(), list);
	}


}
